/*
 * (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * Contributors:
 *     bstefanescu
 */
package org.nuxeo.gwt.habyt.app.client.actions;

import java.io.Serializable;

import org.nuxeo.gwt.habyt.app.client.Action;
import org.nuxeo.gwt.habyt.app.client.ActionContext;
import org.nuxeo.gwt.habyt.app.client.Application;
import org.nuxeo.gwt.habyt.app.client.BusyIndicator;
import org.nuxeo.gwt.habyt.app.client.View;
import org.nuxeo.gwt.habyt.invocation.client.Invocation;
import org.nuxeo.gwt.habyt.invocation.client.InvocationCallback;
import org.nuxeo.gwt.habyt.invocation.client.InvocationResponse;
import org.nuxeo.gwt.habyt.invocation.client.Invoker;
import org.nuxeo.gwt.habyt.invocation.client.Notification;
import org.nuxeo.gwt.habyt.invocation.client.ObjectRef;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
 * 
 */
public class RemoteAction extends Action<ObjectRef> {

    public RemoteAction(String type) {
        super(type);
    }

    public RemoteAction(String type, ObjectRef ref) {
        super(type);
        setData(ref);
    }

    public RemoteAction(String type, ObjectRef ref, String target) {
        super(type);
        setData(ref);
        setTarget(target);
    }

    @Override
    public void loadData(String expr) {
        setData(new ObjectRef(expr));
    }

    protected Notification getOutcome(InvocationResponse result) {
        String clientOutcome = getOutcome();
        if (clientOutcome != null) {
            return Invocation.fromString(clientOutcome);
        }
        return result.getOutcome();
    }

    @Override
    protected void doExecute(final ActionContext ctx) {
        final Invocation invocation = new Invocation(getData(), getType());
        if (ctx.getContent() != null) {
            if (ctx.getContent() instanceof Serializable) {
                invocation.setContent((Serializable) ctx.getContent());
            } else {
                Window.alert("Execution content for remote actions must be serializable");
                return;
            }
        }

        final View view = ctx.findTarget(this);
        final BusyIndicator busy = Application.get().getBusy((Widget) view);
        // TODO too fast ...
        // busy.show();
        Invoker.invoke(invocation, new InvocationCallback() {
            @Override
            public void onSuccess(InvocationResponse result) {
                busy.remove();
                String msg = getMessage();
                if (msg == null) {
                    msg = result.getMessage();
                }
                if (msg != null) {
                    Application.get().showMessage(msg);
                }
                Notification outcome = getOutcome(result);
                if (outcome != null) {
                    if (invocation.sameAs(outcome)) {
                        Window.alert("Infinite Loop detected when invoking "
                                + invocation);
                        return;
                    }
                    Action<?> action = Application.get().getAction(
                            outcome.getAction());
                    action.loadData(outcome.getTarget().toString());
                    action.setTarget(RemoteAction.this.getTarget());
                    action.execute(ctx);
                }
            }

            @Override
            public void onFailure(Throwable caught) {
                busy.remove();
                Window.alert("Invocation failed: " + caught);
            }
        }, true);
    }

}
